﻿using OpenTK;
using System;
using System.Collections.Generic;
using System.Text;
using OpenTK.Graphics.OpenGL4;
using System.Drawing;

namespace Painter3D.RenderSys
{
    /// <summary>
    /// 摄像机 计算View与Projection矩阵相乘后为摄像机矩阵
    /// </summary>
    public abstract class Camera : Component
    {
        public static Camera scenceMainCamera;
        public static Camera uiMainCamera;

        public float width;
        public float height;
        public float nearPlane;
        public float farPlane;

        /// <summary>
        /// 存储单位化的矩形信息
        /// </summary>
        private RectangleF ViewRect = new Rectangle(0, 0, 1, 1);

        protected Camera(Transform transform, float width, float height, float nearPlane, float farPlane) : base(transform)
        {
            this.width = width;
            this.height = height;
            this.nearPlane = nearPlane;
            this.farPlane = farPlane;
        }
        /// <summary>
        /// 获取相机矩阵
        /// </summary>
        /// <returns>相机矩阵</returns>
        public Matrix4 GetCameraMat()
        {
            return GetViewMat() * GetProjectMat();
        }

        /// <summary>
        /// 应用视口位置
        /// </summary>
        public void ApplyViewRect()
        {
            GL.Viewport((int)(ViewRect.X * Window.windowConfig.width),
                        (int)(ViewRect.X * Window.windowConfig.height),
                        (int)(ViewRect.Width * Window.windowConfig.width),
                        (int)(ViewRect.Height * Window.windowConfig.height));
        }

        /// <summary>
        /// 设置渲染位置
        /// </summary>
        /// <param name="x">左侧起始，单位化到[0,1]</param>
        /// <param name="y">下侧起始，单位化到[0,1]</param>
        /// <param name="width">宽度，单位化到[0,1]</param>
        /// <param name="height">高度，单位化到[0,1]</param>
        public void SetViewPort(float x, float y, float width, float height)
        {
            ViewRect.X = (int)(Window.windowConfig.width * x);
            ViewRect.Y = (int)(Window.windowConfig.height * y);
            ViewRect.Width = (int)(Window.windowConfig.height * width);
            ViewRect.Width = (int)(Window.windowConfig.height * height);
        }

        public abstract Matrix4 GetProjectMat();

        public Matrix4 GetViewMat()
        {
            return transform.GetGlobalMat().Inverted();
        }

        public override string ToString()
        {
            return base.ToString() + "W/D:" + width + "/" + height + "(" + nearPlane + "," + farPlane + ")" + Environment.NewLine + "ViewRect:" + ViewRect + Environment.NewLine;
        }

        public Vector3 ScreenToWorld(Vector2 NDC)
        {
            Vector4 vec = new Vector4(NDC.X, NDC.Y, 1.0f, 1.0f);
            Matrix4 mat = GetCameraMat();
            mat.Invert();
            Vector4 WorldPos = vec * mat;
            WorldPos /= WorldPos.W;
            return new Vector3(WorldPos);
        }
    }
}
